"""
安全认证模块 - JWT Token 处理
"""
from datetime import datetime, timedelta, timezone
from typing import Optional
from jose import JWTError, jwt
from passlib.context import CryptContext
from fastapi import HTTPException, status
from werkzeug.security import check_password_hash, generate_password_hash

from  core.config import settings

# 密码加密上下文 - 支持多种哈希算法以兼容旧数据
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")


def verify_password(plain_password: str, hashed_password: str) -> bool:
    """
    验证密码 - 兼容 Werkzeug 和 Bcrypt 两种哈希格式
    
    Args:
        plain_password: 明文密码
        hashed_password: 哈希后的密码
    
    Returns:
        密码是否匹配
    """
    # 先尝试 Werkzeug 格式（原 Flask 项目使用的）
    if hashed_password.startswith('pbkdf2:') or hashed_password.startswith('scrypt:'):
        try:
            return check_password_hash(hashed_password, plain_password)
        except Exception:
            pass
    
    # 然后尝试 Bcrypt 格式（新 FastAPI 项目使用的）
    try:
        return pwd_context.verify(plain_password, hashed_password)
    except Exception:
        return False


def get_password_hash(password: str) -> str:
    """
    获取密码哈希 - 使用 Werkzeug 格式以保持兼容性
    
    Args:
        password: 明文密码
    
    Returns:
        哈希后的密码
    """
    # 使用 Werkzeug 的哈希方法，与原 Flask 项目保持一致
    return generate_password_hash(password)


def create_access_token(data: dict, expires_delta: Optional[timedelta] = None) -> str:
    """
    创建 JWT Access Token
    
    Args:
        data: 要编码的数据（通常包含用户ID等信息）
        expires_delta: 过期时间增量
    
    Returns:
        编码后的 JWT token
    """
    to_encode = data.copy()
    
    if expires_delta:
        expire = datetime.now(timezone.utc) + expires_delta
    else:
        expire = datetime.now(timezone.utc) + timedelta(days=settings.ACCESS_TOKEN_EXPIRE_DAYS)
    
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM)
    return encoded_jwt


def decode_access_token(token: str) -> dict:
    """
    解码 JWT Token
    
    Args:
        token: JWT token 字符串
    
    Returns:
        解码后的数据字典
    
    Raises:
        HTTPException: token 无效或过期
    """
    try:
        payload = jwt.decode(token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM])
        return payload
    except JWTError:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Token无效或已过期",
            headers={"WWW-Authenticate": "Bearer"},
        )

